package com.sf.fy.uav.applet.login.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.sf.fy.uav.applet.login.service.LoginService;
import com.sf.fy.uav.applet.utils.Aes;
import com.sf.fy.uav.applet.utils.HttpClientUtil;
import com.sf.fy.uav.common.awt.JwtUtil;
import com.sf.fy.uav.common.enums.*;
import com.sf.fy.uav.common.exception.BusinessException;
import com.sf.fy.uav.common.utils.PhoneEncoderUtil;
import com.sf.fy.uav.common.utils.RedisPrefixKey;
import com.sf.fy.uav.controller.CouponActivityController;
import com.sf.fy.uav.controller.CouponActivityDetailController;
import com.sf.fy.uav.controller.CouponActivityRecordController;
import com.sf.fy.uav.entity.*;
import com.sf.fy.uav.mapper.*;
import com.sf.fy.uav.order.controller.OrderInfoRest;
import com.sf.fy.uav.rest.*;
import com.sf.fy.uav.user.controller.UserExtraRest;
import com.sf.fy.uav.user.entity.User;
import com.sf.fy.uav.user.entity.UserWallet;
import com.sf.fy.uav.user.mapper.UserMapper;
import com.sf.fy.uav.user.mapper.UserWalletMapper;
import com.sf.fy.uav.user.rest.UserRest;
import com.sf.fy.uav.user.service.IUserService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.TransactionSynchronizationManager;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.web.client.RestTemplate;

import java.math.BigDecimal;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * @author LTQ
 */
@Service
public class LoginServiceImpl implements LoginService {


    private final static Logger logger = LoggerFactory.getLogger(LoginServiceImpl.class);

    //沙盒测试
    private static final String url_sandbox = "https://api.weixin.qq.com/sns/jscode2session";

    @Autowired
    private UserWalletMapper userWalletMapper;

    @Autowired
    private IUserService iUserService;

    @Autowired
    private RestTemplate restTemplate;

    @Value("${wx.appid:wxe6b1552baf2f3303}")
    private String appid;

    @Value("${wx.secret:00fc978b57673faaab9de9e96c035e7b}")
    private String secret;

    @Value("${proxy-url:sfproxy.intsit.sfcloud.local}")
    private String proxyUrl;


    @Value("${is-use-proxy:false}")
    private boolean isUseProxy;

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private CouponActivityController couponActivityController;

    @Autowired
    private CouponActivityMapper couponActivityMapper;


    @Autowired
    private UserCouponMapper userCouponMapper;


    @Autowired
    private CouponActivityDetailController couponActivityDetailController;

    @Autowired
    private OrderInfoRest orderInfoRest;

    @Autowired
    private UserExtraRest userExtraRest;

    @Autowired
    private InvitationCodeMapper invitationCodeMapper;

    @Autowired
    private InvitationCodeRest invitationCodeRest;


    @Autowired
    private ActivityRest activityRest;


    @Autowired
    private InvitationRecordMapper invitationRecordMapper;

    @Autowired
    private InvitationRecordRest invitationRecordRest;

    @Autowired
    private PromotionStatisticsRest promotionStatisticsRest;


    @Autowired
    private PromotionStatisticsMapper promotionStatisticsMapper;

    @Autowired
    private PromotionRecordsMapper promotionRecordsMapper;

    @Autowired
    private PhoneEncoderUtil phoneEncoderUtil;

    @Autowired
    private CouponActivityRecordController couponActivityRecordController;

    @Autowired
    private CouponActivityRecordMapper couponActivityRecordMapper;

    @Autowired
    private CouponMapper couponMapper;

    @Autowired
    private CouponRest couponRest;

    @Autowired
    private UserRest userRest;

    @Override
    public Object decipheringCode(String loginCode) {
        Map<String, String> param = new HashMap<>();
        param.put("appid", appid);
        param.put("secret", secret);
        param.put("js_code", loginCode);
        param.put("grant_type", "authorization_code");
        String body = HttpClientUtil.sendGetJsonRepeatProxy(url_sandbox, proxyUrl, 80, param, isUseProxy);
        Object object = JSONObject.parse(body);
        redisTemplate.opsForValue().set(ServicePrefixEnum.SAME_CITY + RedisPrefixKey.WX_LOGIN_DATA + loginCode, object);
        return object;
    }

    @Override
    public String getAccessToken() {
        String accessToken = (String) redisTemplate.opsForValue().get(ServicePrefixEnum.SAME_CITY + RedisPrefixKey.APPLET_ACCESS_TOKEN);
        if (ObjectUtils.isEmpty(accessToken)) {
            Map<String, String> params = new HashMap<>();
            params.put("grant_type", "client_credential");
            params.put("appid", appid);
            params.put("secret", secret);
            String body = HttpClientUtil.sendGetJsonRepeatProxy("https://api.weixin.qq.com/cgi-bin/token", proxyUrl, 80, params, isUseProxy);
            JSONObject object = JSON.parseObject(body);
            accessToken = object.getString("access_token");
            /*access_token有效时长*/
            int expires_in = object.getInteger("expires_in");
            /*过期时间减去10毫秒：10毫秒是网络连接的程序运行所占用的时间*/
            redisTemplate.opsForValue().set(ServicePrefixEnum.SAME_CITY + RedisPrefixKey.APPLET_ACCESS_TOKEN, accessToken);
            redisTemplate.expire(ServicePrefixEnum.SAME_CITY + RedisPrefixKey.APPLET_ACCESS_TOKEN, expires_in - 5, TimeUnit.SECONDS);

        }
        return accessToken;
    }

    @Override
    public String getStableToken() {
        String accessToken = (String) redisTemplate.opsForValue().get(ServicePrefixEnum.SAME_CITY + RedisPrefixKey.APPLET_STABLE_TOKEN);
        if (ObjectUtils.isEmpty(accessToken)) {
            Map params = new HashMap();
            params.put("grant_type", "client_credential");
            params.put("force_refresh", false);
            params.put("appid", appid);
            params.put("secret", secret);
            String body = com.sf.fy.uav.task.utils.HttpClientUtil.sendPostJsonRepeatProxy("https://api.weixin.qq.com/cgi-bin/stable_token", JSONObject.toJSONString(params), proxyUrl, 80, isUseProxy);
            JSONObject object = JSON.parseObject(body);
            accessToken = object.getString("access_token");
            /*access_token有效时长*/
            int expires_in = object.getInteger("expires_in");
            /*过期时间减去10毫秒：10毫秒是网络连接的程序运行所占用的时间*/
            redisTemplate.opsForValue().set(ServicePrefixEnum.SAME_CITY + RedisPrefixKey.APPLET_STABLE_TOKEN, accessToken);
            redisTemplate.expire(ServicePrefixEnum.SAME_CITY + RedisPrefixKey.APPLET_STABLE_TOKEN, expires_in - 5, TimeUnit.SECONDS);
        }
        return accessToken;
    }


    @Override
    public String loginByWechat(String loginCode, String encryptedData, String iv, String scene) {
        Object object;
        object = redisTemplate.opsForValue().get(ServicePrefixEnum.SAME_CITY + RedisPrefixKey.WX_LOGIN_DATA + loginCode);
        if (ObjectUtils.isEmpty(object)) {
            object = this.decipheringCode(loginCode);
        }
        String sessionKey = (String) ((JSONObject) object).get("session_key");
        if (ObjectUtils.isEmpty(sessionKey)) {
            throw new BusinessException(ErrorEnum.DECRYPTING_CODE_EXCEPTION);
        }
        String data = null;
        try {
            data = Aes.decrypt(encryptedData, sessionKey, iv);
        } catch (Exception e) {
            e.printStackTrace();
        }
        JSONObject jsonObject = JSONObject.parseObject(data);
        String phoneNumber = (String) jsonObject.get("phoneNumber");
        String countryCode = (String) jsonObject.get("countryCode");
        String openid = ((JSONObject) object).getString("openid");
        return this.managerUserAndGetToken(phoneNumber, countryCode, openid, scene, ServicePrefixEnum.SAME_CITY.name());
    }

    @Override
    public String loginBySfExpressData(String mobile, String openId) {
        return this.managerUserAndGetToken(mobile, "86", openId, null, ServicePrefixEnum.SAME_CITY_H5.name());
    }

    @Override
    public String loginByPhoneNumber(String phone, String loginCode, String scene) {
        String openid = null;
        if (!ObjectUtils.isEmpty(loginCode)) {
            Object object;
            object = redisTemplate.opsForValue().get(ServicePrefixEnum.SAME_CITY + RedisPrefixKey.WX_LOGIN_DATA + loginCode);
            if (ObjectUtils.isEmpty(object)) {
                object = this.decipheringCode(loginCode);
            }
            openid = (String) ((JSONObject) object).get("openid");
        }
        return this.managerUserAndGetToken(phone, "86", openid, scene, ServicePrefixEnum.SAME_CITY.name());
    }

    private String managerUserAndGetToken(String phoneNumber, String countryCode, String openid, String scene, String servicePrefixEnum) {
        Date date = new Date();
        QueryWrapper<User> userQueryWrapper = new QueryWrapper<>();
        String encryptPhone = phoneEncoderUtil.encryptString(phoneNumber);
        userQueryWrapper.eq("phone_number", encryptPhone);
        Integer platformCode;
        if (ServicePrefixEnum.SAME_CITY.name().equals(servicePrefixEnum)) {
            platformCode = PlatformCodeEnum.FY_EXPRESS.getCode();
        } else if (ServicePrefixEnum.SAME_CITY_H5.name().equals(servicePrefixEnum)) {
            platformCode = PlatformCodeEnum.CX.getCode();
        } else {
            platformCode = null;
        }
        List list = new ArrayList<>();
        list.add(PlatformCodeEnum.FY_EXPRESS.getCode());
        list.add(PlatformCodeEnum.CX.getCode());
        List<User> users = userRest.getList(encryptPhone, countryCode, list);
        User user;
        if (CollectionUtils.isEmpty(users)) {
            user = new User();
            user.setId(UUID.randomUUID().toString().replaceAll("-", ""));
            user.setPhoneNumber(phoneNumber);
            user.setCountryCode(countryCode);
            user.setStatus(UserStatusEnum.NORMAL.getValue());
            user.setPlatformCode(platformCode);
            user.setCreateTime(date);
            user.setUpdateTime(date);
            iUserService.insert(user);
            UserWallet userWallet = new UserWallet();
            userWallet.setCreateTime(date);
            userWallet.setUpdateTime(date);
            userWallet.setUserId(user.getId());
            userWallet.setBalance(new BigDecimal(0));
            userWallet.setAccumulatedRewards(new BigDecimal(0));
            userWalletMapper.insert(userWallet);
            if (!ObjectUtils.isEmpty(scene)) {
                InvitationCode invitationCode = invitationCodeMapper.selectById(scene);

                if (!ObjectUtils.isEmpty(invitationCode)) {
                    String invitationUserId = invitationCode.getUserId();
                    Boolean b = activityRest.checkEffectiveness(invitationCode.getActivityId());
                    if (b) {
                        //活动时间内才记录邀请记录
                        InvitationRecord invitationRecord = new InvitationRecord();
                        invitationRecord.setCreateTime(date);
                        invitationRecord.setUpdateTime(date);
                        invitationRecord.setDeleted(false);
                        invitationRecord.setInvitationCodeId(invitationCode.getId());
                        invitationRecord.setUserId(user.getId());
                        invitationRecordMapper.insert(invitationRecord);


                        String activityId = invitationCode.getActivityId();
                        Activity activity = activityRest.getSettings(activityId);
                        if (!ObjectUtils.isEmpty(activity)) {
                            //处理统计数据
                            PromotionStatistics promotionStatistics = promotionStatisticsRest.getPromotionStatistics(invitationUserId, activityId);
                            if (!ObjectUtils.isEmpty(promotionStatistics)) {
                                promotionStatistics.setUpdateTime(date);
                                Long cnt = invitationRecordRest.selectCountByInvitationCodeId(invitationCode.getId());
                                promotionStatistics.setSubscriberNumber(cnt.intValue());
                                promotionStatisticsMapper.updateById(promotionStatistics);

                            }
                        }
                    }
                }
            }
        } else {
            user = users.get(0);
            if (!UserStatusEnum.NORMAL.getValue().equals(user.getStatus())) {
                throw new BusinessException(ErrorEnum.ABNORMAL_USER);
            }
        }
        String userId = user.getId();
        if (!ObjectUtils.isEmpty(openid)) {
            redisTemplate.opsForValue().set(servicePrefixEnum + RedisPrefixKey.APPLET_OPENID + userId, openid);
        }
        //准备存放在IWT中的自定义数据
        Map<String, Object> info = new HashMap<>(2);
        info.put("phone_number", phoneNumber);
        info.put("country_code", countryCode);
        //生成JWT字符串
        String token = JwtUtil.sign(userId, info);
        logger.info("### 登录成功, token={} ###", token);

//        iUserService.dealLogin(date, userId);
        return token;
    }


}
